/*
 * Contexto.cpp
 *
 *  Created on: 03/06/2010
 *      Author: sebastian
 */

#include "Contexto.h"
#include "Aritmetico.h"

	Contexto::Contexto(char* data, string nombre){
		this->nombre = nombre; //el nombre esta en la clave no en elemento
		this->tabla = new TTablaFreq;
		//convencion: [frecTotal][cantEsc][cantEOF][cantCaract][carac1][frec1]..[caracN][frecN]
		int indice = 0;
		int longitud = sizeof(unsigned);
		memcpy(&frecuenciaTotal,data,longitud);
		indice += longitud;
		memcpy(&cantidadEscapes,&data[indice],longitud);
		indice += longitud;
		memcpy(&cantidadEOF,&data[indice],longitud);
		indice += longitud;
		memcpy(&cantidadDeCaracteres,&data[indice],longitud);
		indice += longitud;
		for(int j=0;j<(int)this->cantidadDeCaracteres;j++){
			char aux = NULL;
			longitud = sizeof(char);
			memcpy(&aux,&data[indice],longitud);
			indice += longitud;
			unsigned frecAux = 0;
			longitud = sizeof(unsigned);
			memcpy(&frecAux,&data[indice],longitud);
			indice += longitud;
			this->tabla->insert(pair<char,unsigned> (aux,frecAux));
		}
	}

	char* Contexto::contextoABytes(int * tamanioData){
		(*tamanioData) = this->cantidadDeCaracteres*((sizeof(char)+sizeof(unsigned))) + (sizeof(unsigned)*4);
		char* data = new char[(*tamanioData)];
		//convencion: [frecTotal][cantEsc][cantCaract][carac1][frec1]..[caracN][frecN]
		int indice = 0;
		unsigned int longitud = sizeof(unsigned);
		memcpy(data,&frecuenciaTotal,longitud);
		indice += longitud;
		memcpy(&data[indice],&cantidadEscapes,longitud);
		indice += longitud;
		memcpy(&data[indice],&cantidadEOF,longitud);
		indice += longitud;
		memcpy(&data[indice],&cantidadDeCaracteres,longitud);
		indice += longitud;
		TTablaFreq::iterator it = tabla->begin();
		for(int j=0;j<(int)this->cantidadDeCaracteres;j++){
			char aux = it->first;
			longitud = sizeof(char);
			memcpy(&data[indice],&aux,longitud);
			indice += longitud;
			unsigned frecAux = it->second;
			longitud = sizeof(unsigned);
			memcpy(&data[indice],&frecAux,longitud);
			indice += longitud;
			it++;
		}

		return data;
	}

	Contexto::Contexto(string nombre){
		this->nombre = nombre;
		this->cantidadDeCaracteres = 0;
		this->cantidadEscapes = 1;
		this->cantidadEOF = 0;
		this->frecuenciaTotal = 1;
		this->tabla = new TTablaFreq;
	}

	Contexto::~Contexto(){
		delete tabla;
	}

	TTablaFreq* Contexto::getTabla(){
		return tabla;
	}

	void Contexto::actualizar(TLetraExt caracter){

		if(caracter != FIN_DE_ARCHIVO){
			TTablaFreq::iterator* it = buscarCaracter(caracter);
			if((*it) != this->tabla->end()){
				//actualizo el caracter
				(*it)->second++;
			}else{
				//doy de alta el caracter
				tabla->insert(pair<TLetra,unsigned>(caracter,(unsigned)1));
				this->cantidadDeCaracteres++;
			}
			this->frecuenciaTotal++;
			delete it;
		}else{
			actualizarEOF();
		}
	}

	map<TLetra,unsigned>::iterator* Contexto::buscarCaracter(TLetra c){
		TTablaFreq::iterator* it = new TTablaFreq::iterator;
		bool yaEsta = false;

		*it = this->tabla->begin();

		while((!yaEsta)&&(*it != this->tabla->end())){
			if((*it)->first == c){
				yaEsta = true;
			}else{
				++(*it);
			}
		}
		return it;
	}

	void Contexto::actualizarEsc(){
		this->cantidadEscapes++;
		this->frecuenciaTotal++;
	}

	void Contexto::actualizarEOF(){
		this->cantidadEOF++;
		this->frecuenciaTotal++;
	}

	unsigned Contexto::getCantidadDeEOF(){
		return this->cantidadEOF;
	}

	unsigned Contexto::getCantidadDeEscapes(){
		return this->cantidadEscapes;
	}

	string Contexto::getNombre(){
		return this->nombre;
	}

	unsigned Contexto::getFrecuenciaTotal(){
		return this->frecuenciaTotal;
	}

	unsigned Contexto::getCantidadDeCaracteres(){
		return this->cantidadDeCaracteres;
	}

	void Contexto::agregarCaracter(pair<TLetra,unsigned> par){
		map<TLetra,unsigned>::iterator* it = buscarCaracter(par.first);
		if(*it != tabla->end()){
			//reemplazo el valor por el nuevo
			this->frecuenciaTotal -= (*it)->second;
			(*it)->second = par.second;
		}else{
			//doy de alta
			tabla->insert(par);
			this->cantidadDeCaracteres++;
		}
		this->frecuenciaTotal += par.second;
		delete it;
	}

	void Contexto::setEsc(unsigned cantidad){
		int aux = cantidad -this->cantidadEscapes;
		if(aux > 0){
			this->frecuenciaTotal += aux;
			this->cantidadEscapes = cantidad;
		}
	}

	void Contexto::setEOF(unsigned cantidad){
		int aux = cantidad -this->cantidadEOF;
		if(aux > 0){
			this->frecuenciaTotal += aux;
			this->cantidadEOF = cantidad;
		}
	}

	TLetraExt* Contexto::devolverCaracter(TLetraExt caracter){

		TLetraExt* respuesta = NULL;

		if( caracter != FIN_DE_ARCHIVO){

			TTablaFreq::iterator* it = buscarCaracter((TLetra)caracter);

			if(*it != tabla->end())
				respuesta = new TLetraExt (caracter);
			delete it;

		} else {
			if (this->cantidadEOF > 0) {
				respuesta = new TLetraExt(FIN_DE_ARCHIVO);
			}
		}
		return respuesta;
	}
